const { parentPort, workerData } = require("worker_threads");
const { spawn } = require("child_process");
const fs = require("fs/promises");
const path = require("path");
const logger = require("winston");

const now = new Date();
const year = now.getFullYear(); // 获取年份，例如 2025
const month = String(now.getMonth() + 1).padStart(2, "0"); // 获取月份，从 0 开始，需要加 1，并补零
const day = String(now.getDate()).padStart(2, "0"); // 获取日期，并补零

// 配置日志
logger.configure({
  level: "debug",
  transports: [
    new logger.transports.Console({
      level: "info",
      format: logger.format.combine(
        logger.format.timestamp(),
        logger.format.printf(
          (info) => `${info.timestamp} - ${info.level} - ${info.message}`
        )
      ),
    }),
    new logger.transports.File({
      level: "debug",
      filename: `worker_${year}${month}${day}.log`,
      format: logger.format.combine(
        logger.format.timestamp(),
        logger.format.printf(
          (info) => `${info.timestamp} - ${info.level} - ${info.message}`
        )
      ),
      maxsize: 10485760, // 10MB
      maxFiles: 5,
      tailable: true,
    }),
  ],
});

parentPort.on("message", async (task) => {
  try {
    const { videoInfo, outputDir } = task;

    // 2. 创建 HLS 唯一目录（原有逻辑保留）
    const uniqueDir = path.resolve(outputDir, videoInfo.id);
    await fs.mkdir(uniqueDir, { recursive: true });

    // 3. 定义关键路径
    const m3u8Path = path.resolve(uniqueDir, "playlist.m3u8");

    // 6. 处理已有 m3u8 文件（新增文件处理）
    try {
      const m3u8Content = await fs.readFile(m3u8Path, "utf-8");
      if (m3u8Content.includes("#EXT-X-ENDLIST")) {
        return;
      }
    } catch (err) {
      logger.debug("未找到已有 m3u8 文件");
    }

    // 4. 检查已有分片并计算续传起点（新增核心逻辑）
    const getLastSegmentNumber = async () => {
      try {
        const files = await fs.readdir(uniqueDir);
        const tsFiles = files.filter((f) => f.match(/segment_\d+\.ts/));

        if (tsFiles.length === 0) return 0;

        // 提取最大分片编号（示例文件名：segment_001.ts）
        const lastNumber = Math.max(
          ...tsFiles.map((f) => {
            const match = f.match(/segment_(\d+)\.ts/);
            return match ? parseInt(match[1], 10) : -1;
          })
        );

        return lastNumber >= 0 ? lastNumber + 1 : 0;
      } catch (err) {
        return 0;
      }
    };

    // 修改后的FFmpeg参数配置
    const getResumePosition = async (uniqueDir) => {
      try {
        // 1. 通过m3u8文件计算已处理时长
        const m3u8Content = await fs.readFile(
          path.join(uniqueDir, "playlist.m3u8"),
          "utf-8"
        );

        // 2. 解析总时长（示例格式：#EXT-X-TARGETDURATION:10）
        const matches = m3u8Content.match(/#EXTINF:([\d.]+)/gi);
        const durations = matches
          ? matches.map((m) => parseFloat(m.replace(/#EXTINF:/i, "")))
          : [];

        return durations.reduce((a, b) => a + b, 0); // 返回已处理总秒数
      } catch {
        return 0; // 没有历史记录则从头开始
      }
    };

    // 5. 动态设置转码参数（修改参数生成逻辑）
    const startNumber = await getLastSegmentNumber();
    const needAppend = startNumber > 0; // 判断是否需要续传

    // 3. 获取续传时间点
    const resumeTime = await getResumePosition(uniqueDir);

    logger.debug(
      `startNumber=${startNumber}，needAppend=${needAppend}，resumeTime=${resumeTime}`
    );

    // 4. 启动 FFmpeg 进程
    const ffmpegArgs = [
      // 1. 时间定位参数必须放在输入文件前（快速定位模式）
      "-ss",
      resumeTime.toFixed(3),

      // 2. 输入文件声明
      "-i",
      videoInfo.filepath,

      // 3. 视频编码配置
      "-c:v",
      "h264_nvenc",
      "-preset",
      "p4",

      // 4. 关键帧控制（强制对齐分片时间）
      "-force_key_frames",
      "expr:gte(t,n_forced*10)", // 动态匹配hls_time

      // 5. HLS基础参数
      "-f", // 显式指定格式！！！重要修复
      "hls", // 使用HLS复用器
      "-hls_time",
      "10",
      "-hls_list_size",
      "0",

      // 6. 分片编号控制核心参数
      "-hls_segment_filename",
      `${uniqueDir}/segment_%03d.ts`,
      "-segment_start_number", // 替换原start_number参数！！！关键修改
      startNumber.toString(),

      // 7. 时间戳处理（解决编号跳跃问题）
      "-reset_timestamps",
      "1", // 重置时间戳计数器！！！关键修改
      "-output_ts_offset",
      resumeTime.toFixed(3), // 补偿输出时间偏移

      // 8. 动态标志配置
      "-hls_flags",
      needAppend
        ? "append_list+temp_file+omit_endlist" // 续传模式
        : "delete_segments", // 全新模式

      // 9. 异常处理参数
      "-avoid_negative_ts",
      "make_non_negative", // 更安全的时间戳处理

      // 10. 输出目标
      m3u8Path,
    ];

    logger.debug(`ffmpeg执行命令：${ffmpegArgs}`);

    // 启动FFmpeg进程
    const ffmpegProcess = spawn("ffmpeg", ffmpegArgs);

    // 进程管理
    const processPromise = new Promise((resolve, reject) => {
      ffmpegProcess.on("exit", (code, signal) => {
        if (code === null) {
          logger.error(`FFmpeg 被信号终止: ${signal}`);
        } else {
          logger.error(`FFmpeg 退出码: ${code}`);
        }
        if (code === 0) {
          resolve({ status: "completed", videoId: videoInfo.id });
        } else {
          reject(new Error(`FFmpeg exited with code ${code}`));
        }
      });

      ffmpegProcess.on("error", (err) => {
        reject(new Error(`FFmpeg error: ${err.message}`));
      });
    });

    // 等待转码完成
    await processPromise;

    // 更新m3u8文件
    await fs.appendFile(m3u8Path, "\n#EXT-X-ENDLIST");

    parentPort.postMessage({
      success: true,
      videoId: videoInfo.id,
      hlsPath: `/hls/${videoInfo.id}/playlist.m3u8`,
    });
  } catch (err) {
    parentPort.postMessage({
      error: err.message,
      videoId: task.videoInfo.id,
    });
  }
});
